/*
 *  Startup Code for MIPS32 CPU-core
 *
 *  Copyright (c) 2003  Wolfgang Denk <wd@denx.de>
 *  Copyright (c) 2013 Qualcomm Atheros, Inc.
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */


#include <config.h>
#include <version.h>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#ifdef CONFIG_ATHEROS
#   include <atheros.h>
#else
#   include <ar7240_soc.h>
#   define ATH_SPI_CLOCK    0xbf000004
#endif

#define AR7100_SPI_CLOCK  0xbf000004

#define ATH_APB_BASE        0xB8000000  /* KSEG1ADDR(0x18000000) */
#define ATH_GPIO_BASE       ATH_APB_BASE+0x00040000
#define ATH_GPIO_OE         ATH_GPIO_BASE+0x0
#define ATH_GPIO_OUT        ATH_GPIO_BASE+0x8
#define ATH_GPIO_OUT_FUNCTION0      ATH_GPIO_BASE+0x2c
#define ATH_GPIO_OUT_FUNCTION1      ATH_GPIO_BASE+0x30
#define ATH_GPIO_OUT_FUNCTION2      ATH_GPIO_BASE+0x34
#define ATH_GPIO_OUT_FUNCTION3      ATH_GPIO_BASE+0x38
#define ATH_GPIO_OUT_FUNCTION4      ATH_GPIO_BASE+0x3c
#define ATH_GPIO_OUT_FUNCTION5      ATH_GPIO_BASE+0x40
#define ATH_GPIO_FUNCTION           ATH_GPIO_BASE+0x6c


#define RVECENT(f,n) \
   b f; nop

#define XVECENT(f,bev) \
   b f     ;           \
   li k0,bev

    .set noreorder

    .globl _start_bootstrap
    .text
_start_bootstrap:
    RVECENT(reset,0)    /* U-boot entry point */
    RVECENT(reset,1)    /* software reboot */
    RVECENT(romReserved,2)
    RVECENT(romReserved,3)
    RVECENT(romReserved,4)
    RVECENT(romReserved,5)
    RVECENT(romReserved,6)
    RVECENT(romReserved,7)
    RVECENT(romReserved,8)
    RVECENT(romReserved,9)
    RVECENT(romReserved,10)
    RVECENT(romReserved,11)
    RVECENT(romReserved,12)
    RVECENT(romReserved,13)
    RVECENT(romReserved,14)
    RVECENT(romReserved,15)
    RVECENT(romReserved,16)
    RVECENT(romReserved,17)
    RVECENT(romReserved,18)
    RVECENT(romReserved,19)
    RVECENT(romReserved,20)
    RVECENT(romReserved,21)
    RVECENT(romReserved,22)
    RVECENT(romReserved,23)
    RVECENT(romReserved,24)
    RVECENT(romReserved,25)
    RVECENT(romReserved,26)
    RVECENT(romReserved,27)
    RVECENT(romReserved,28)
    RVECENT(romReserved,29)
    RVECENT(romReserved,30)
    RVECENT(romReserved,31)
    RVECENT(romReserved,32)
    RVECENT(romReserved,33)
    RVECENT(romReserved,34)
    RVECENT(romReserved,35)
    RVECENT(romReserved,36)
    RVECENT(romReserved,37)
    RVECENT(romReserved,38)
    RVECENT(romReserved,39)
    RVECENT(romReserved,40)
    RVECENT(romReserved,41)
    RVECENT(romReserved,42)
    RVECENT(romReserved,43)
    RVECENT(romReserved,44)
    RVECENT(romReserved,45)
    RVECENT(romReserved,46)
    RVECENT(romReserved,47)
    RVECENT(romReserved,48)
    RVECENT(romReserved,49)
    RVECENT(romReserved,50)
    RVECENT(romReserved,51)
    RVECENT(romReserved,52)
    RVECENT(romReserved,53)
    RVECENT(romReserved,54)
    RVECENT(romReserved,55)
    RVECENT(romReserved,56)
    RVECENT(romReserved,57)
    RVECENT(romReserved,58)
    RVECENT(romReserved,59)
    RVECENT(romReserved,60)
    RVECENT(romReserved,61)
    RVECENT(romReserved,62)
    RVECENT(romReserved,63)
    XVECENT(romExcHandle,0x200) /* bfc00200: R4000 tlbmiss vector */
    RVECENT(romReserved,65)
    RVECENT(romReserved,66)
    RVECENT(romReserved,67)
    RVECENT(romReserved,68)
    RVECENT(romReserved,69)
    RVECENT(romReserved,70)
    RVECENT(romReserved,71)
    RVECENT(romReserved,72)
    RVECENT(romReserved,73)
    RVECENT(romReserved,74)
    RVECENT(romReserved,75)
    RVECENT(romReserved,76)
    RVECENT(romReserved,77)
    RVECENT(romReserved,78)
    RVECENT(romReserved,79)
    XVECENT(romExcHandle,0x280) /* bfc00280: R4000 xtlbmiss vector */
    RVECENT(romReserved,81)
    RVECENT(romReserved,82)
    RVECENT(romReserved,83)
    RVECENT(romReserved,84)
    RVECENT(romReserved,85)
    RVECENT(romReserved,86)
    RVECENT(romReserved,87)
    RVECENT(romReserved,88)
    RVECENT(romReserved,89)
    RVECENT(romReserved,90)
    RVECENT(romReserved,91)
    RVECENT(romReserved,92)
    RVECENT(romReserved,93)
    RVECENT(romReserved,94)
    RVECENT(romReserved,95)
    XVECENT(romExcHandle,0x300) /* bfc00300: R4000 cache vector */
    RVECENT(romReserved,97)
    RVECENT(romReserved,98)
    RVECENT(romReserved,99)
    RVECENT(romReserved,100)
    RVECENT(romReserved,101)
    RVECENT(romReserved,102)
    RVECENT(romReserved,103)
    RVECENT(romReserved,104)
    RVECENT(romReserved,105)
    RVECENT(romReserved,106)
    RVECENT(romReserved,107)
    RVECENT(romReserved,108)
    RVECENT(romReserved,109)
    RVECENT(romReserved,110)
    RVECENT(romReserved,111)
    XVECENT(romExcHandle,0x380) /* bfc00380: R4000 general vector */
    RVECENT(romReserved,113)
    RVECENT(romReserved,114)
    RVECENT(romReserved,115)
    RVECENT(romReserved,116)
    RVECENT(romReserved,116)
    RVECENT(romReserved,118)
    RVECENT(romReserved,119)
    RVECENT(romReserved,120)
    RVECENT(romReserved,121)
    RVECENT(romReserved,122)
    RVECENT(romReserved,123)
    RVECENT(romReserved,124)
    RVECENT(romReserved,125)
    RVECENT(romReserved,126)
    RVECENT(romReserved,127)

    /* We hope there are no more reserved vectors!
     * 128 * 8 == 1024 == 0x400
     * so this is address R_VEC+0x400 == 0xbfc00400
     */
    .align 4
reset:

    /*
     * Clearing CP0 registers - This is generally required for the MIPS-24k
     * core used by Atheros.
     */
    mtc0    zero, $0
    mtc0    zero, $1
    mtc0    zero, $2
    mtc0    zero, $3
    mtc0    zero, $4
    mtc0    zero, $5
    mtc0    zero, $6
    mtc0    zero, $7
    mtc0    zero, $8
    mtc0    zero, $9
    mtc0    zero, $10
    mtc0    zero, $11
    li  t0, 0x10000004
    mtc0    t0, $12
    mtc0    zero, $13
    mtc0    zero, $14
    mtc0    zero, $15
    mtc0    zero, $16
    
#ifdef CONFIG_MACH_QCA955x
/*
 * Workaround recommnded by MIPS for the Scorpion Freeze issue
 */
#define CONFIG_SCO_JRCD     1
#define CONFIG_SCO_IAGN     !CONFIG_SCO_JRCD

#if CONFIG_SCO_IAGN && CONFIG_SCO_JRCD
#error Both CONFIG_SCO_IAGN and CONFIG_SCO_JRCD set
#endif

#if CONFIG_SCO_JRCD
    /*
     * JR Cache Prediction Disable. Disables JR target address prediction.
     * Bit [0], CP0 Register 16, Select 6
     *  0 - JR cache target address prediction is enabled.
     *  1 - JR cache target address prediction is not enabled.
     */
    mfc0    t0, $16,    6
    li  t1, (1 << 0)
    or  t0, t0, t1
    mtc0    t0, $16,    6
#endif

#if CONFIG_SCO_IAGN
    /*
     * Bit [25], CP0 Register 16, Select 7
     * Selective control of out-of-order behavior: issue ALU-side or
     * load/store-side instructions (respectively) in program order.
     */
    mfc0    t0, $16,    7
    li  t1, (1 << 25)
    or  t0, t0, t1
    mtc0    t0, $16,    7
#endif
#endif /* CONFIG_MACH_QCA955x */

#if !defined(CONFIG_WASP_SUPPORT)
    mtc0    zero, $17
#endif
    mtc0    zero, $18
    mtc0    zero, $19
#if !defined(CONFIG_WASP_SUPPORT)
    mtc0    zero, $20
    mtc0    zero, $21
    mtc0    zero, $22
#endif
#ifndef CONFIG_HORNET_EMU
    mtc0    zero, $23
#endif
    mtc0    zero, $24
    mtc0    zero, $25
    mtc0    zero, $26
    mtc0    zero, $27
    mtc0    zero, $28
#if defined(CONFIG_WASP_SUPPORT) || defined(CONFIG_MACH_QCA955x) || defined(CONFIG_MACH_QCA953x) || defined(CONFIG_MACH_QCA956x)
    mtc0    zero, $29   # C0_TagHi
    mtc0    zero, $28, 2    # C0_DTagLo
    mtc0    zero, $29, 2    # C0_DTagHi
#endif

    /*
     * Clear watch registers.
     */

    mtc0    zero, CP0_WATCHLO
    mtc0    zero, CP0_WATCHHI

    /* STATUS register */
    mfc0    k0, CP0_STATUS
    li  k1, ~ST0_IE
    and k0, k1
        mtc0    zero, CP0_CAUSE
    mtc0    k0, CP0_STATUS

    /* CAUSE register */
    mtc0    zero, CP0_CAUSE

    /* Init Timer */
    mtc0    zero, CP0_COUNT
    mtc0    zero, CP0_COMPARE

    /* CONFIG0 register */
    li  t0, CONF_CM_UNCACHED
    mtc0    t0, CP0_CONFIG

#ifdef CONFIG_ATH_NAND_BR
    /*
     * Clear WDT that was setup in first stage for
     * NAND Boot-ROM
     */
    li  t0, 0xb8060008
    sw  zero,   0(t0)
#endif /* CONFIG_ATH_NAND_BR */

    /* Initialize GOT pointer.*/
    bal     1f
    nop
    .word   _GLOBAL_OFFSET_TABLE_
    1:
    move    gp, ra
    lw      t1, 0(ra)
    move    gp, t1

#define DCACHE_16K  0
#if DCACHE_16K && defined(CONFIG_WASP_SUPPORT)
    mfc0    t2, CP0_CONFIG
    or  t2, t2, 0x80000
    mtc0    t2, CP0_CONFIG
    nop

    mfc0    t2, CP0_CONFIG, 1
    and t2, t2, ~(0xe000)
    or  t2, t2, 0x3000
    mtc0    t2, CP0_CONFIG, 1
    nop

    mfc0    t2, CP0_CONFIG
    and t2, t2, ~(0x80000)
    mtc0    t2, CP0_CONFIG

#endif  /* DCACHE_16K */

#if (defined(CONFIG_MACH_HORNET) && defined(CONFIG_HORNET_1_1_WAR)) || defined(CONFIG_MACH_QCA956x)
/**************************************************************************/
/*
 * WAR: Hornet 1.1 currently need a reset once we boot to let the resetb has
 *      enough time to stable, so that trigger reset at 1st boot, system team
 *      is investigaing the issue, will remove in short
 */

do_reset_normal:

    li  t7, 0xbd000000
    lw  t8, 0(t7)            // t8 : value of 0xbd000000
    li  t9, 0x12345678
    sw  t9, 0(t7) 
    bne t8, t9, do_reset     // if value of 0xbd000000 != 0x12345678 , go to do_reset
    nop
    b   normal_path

do_reset:
    li  t7, 0xb806001c       // load reset register 0x1806001c
    lw  t8, 0(t7)
    li  t9, 0x1000000        // bit24, fullchip reset
    or t8, t8, t9         // t8:  set bit 18
    sw  t8, 0(t7)

normal_path:
#endif /* CONFIG_MACH_HORNET */

/**************************************************************************/

    /* Initialize any external memory.
     */
#if defined(CONFIG_AR7100) || defined(CONFIG_AR7240) || defined(CONFIG_MACH_QCA955x) || defined(CONFIG_MACH_QCA953x) || defined(CONFIG_MACH_QCA956x)
    la      t9, lowlevel_init
    jalr    t9
    nop
    nop

#if defined(CONFIG_MACH_HORNET)
    la      t9, hornet_ddr_init
    jalr    t9
    nop
    nop
#endif

    la  t0, rel_start
    j   t0
    nop
#endif

rel_start:

#if defined(CONFIG_AR7100) || defined(CONFIG_AR7240) || defined(CONFIG_ATHEROS)
    /* REMAP_DISABLE */
    li  a0, KSEG1ADDR(ATH_SPI_CLOCK)
#if defined(CONFIG_MACH_QCA955x) || defined(CONFIG_MACH_QCA953x) || defined(CONFIG_MACH_QCA956x)
    li  t0, 0x246
#elif defined(CONFIG_WASP_SUPPORT)
    li  t0, 0x243
#else
    li  t0, 0x43
#endif
    sw  t0, 0(a0)
#endif

#if defined(CONFIG_AR9100) && defined(CFG_HOWL_1_2)
    /* Disable remap for parallel flash */
    li  t7, AR9100_FLASH_CONFIG;
    lw  t8, 0(t7);
    li  t9, 0xffbf0000;
    and t8, t8, t9;
    li  t9, 0x22fc;
    or  t8, t8, t9;
    li  t9, 0xffcfffff; /* scale = 0 */
    and t8, t8, t9;
    sw  t8, 0(t7);

#endif

    /* Initialize caches...
     */
    la      t9, simple_mips_cache_reset
    jalr    t9
    nop

    /* ... and enable them.
     */
#if defined(CONFIG_WASP_SUPPORT) && !defined(CONFIG_ATH_NAND_BR)
    li  t7, KSEG1ADDR(AR7240_REV_ID)
    lw  t7, 0(t7)
    andi    t9, t7, 0xf
    bne zero,   t9, 1f
    nop

    li  t0, CONF_CM_UNCACHED
    j   2f
    nop
#endif

1:  li  t0, CONF_CM_CACHABLE_NONCOHERENT
2:  mtc0    t0, CP0_CONFIG

#if !defined(CFG_INIT_STACK_IN_SRAM)
#if !defined(CONFIG_AR7100) && !defined(CONFIG_AR7240)
    /* Set up temporary stack.
     */
    li  a0, CFG_INIT_SP_OFFSET
    la      t9, mips_cache_lock
    jalr    t9
    nop
#endif

#if defined(CONFIG_AR7100) || defined(CONFIG_AR7240)
    la  t9, mips_cache_lock_24k
    jalr    t9
    nop
#endif
#endif /* CFG_INIT_STACK_IN_SRAM */

#if 1 /* all LED on*/
    bal setLed
    nop
#endif

#if defined(CONFIG_WASP_SUPPORT) || defined(CFG_INIT_STACK_IN_SRAM)
    li  t0, CFG_INIT_SRAM_SP_OFFSET /* Setup stack in SRAM */
#else
    li  t0, CFG_SDRAM_BASE + CFG_INIT_SP_OFFSET
#endif
    la  sp, 0(t0)

    la  t9, bootstrap_board_init_f
    j   t9
    nop


/*
 * void bootstrap_relocate_code (addr_sp, gd, addr_moni)
 *
 * This "function" does not return, instead it continues in RAM
 * after relocating the monitor code.
 *
 * a0 = addr_sp
 * a1 = gd
 * a2 = destination address
 */
    .globl  bootstrap_relocate_code
    .ent    bootstrap_relocate_code
bootstrap_relocate_code:
    move    sp, a0      /* Set new stack pointer        */

    li  t0, BOOTSTRAP_CFG_MONITOR_BASE
    la  t3, in_ram
    lw  t2, -12(t3) /* t2 <-- uboot_end_data_bootsrap   */

    /*
     * Ideally, following line is not needed. However,
     * the behaviour is flaky without it. U-boot boots on
     * some boards, and doesn't on some boards. Even on the
     * boards it boots, it doesn't boot all the time.
     *
     * Adding 256k to what needs to be read in actually.
     * This introduces some delay that seems to help boot.
     */
    li  t3, (256 << 10)

    add t2, t3
    move    t1, a2

    /*
     * Fix GOT pointer:
     *
     * New GOT-PTR = (old GOT-PTR - BOOTSTRAP_CFG_MONITOR_BASE) + Destination Address
     */
    move    t6, gp
    sub gp, BOOTSTRAP_CFG_MONITOR_BASE
    add gp, a2          /* gp now adjusted      */
    sub t6, gp, t6      /* t6 <-- relocation offset */

    /*
     * t0 = source address
     * t1 = target address
     * t2 = source end address
     */
1:
    lw  t3, 0(t0)
    sw  t3, 0(t1)
    addu    t0, 4
    ble t0, t2, 1b
    addu    t1, 4           /* delay slot           */

    /* If caches were enabled, we would have to flush them here.
     */
    bal mips_cache_flush
    nop
    
    /* Jump to where we've relocated ourselves.
     */
    addi    t0, a2, in_ram - _start_bootstrap
    j   t0
    nop

    .word   uboot_end_data_bootstrap
    .word   uboot_end_bootstrap
    .word   num_got_entries

in_ram:
    /* Now we want to update GOT.
     */
    lw  t3, -4(t0)  /* t3 <-- num_got_entries   */
    addi    t4, gp, 8   /* Skipping first two entries.  */
    li  t2, 2
1:
    lw  t1, 0(t4)
    beqz    t1, 2f
    add t1, t6
    sw  t1, 0(t4)
2:
    addi    t2, 1
    blt t2, t3, 1b
    addi    t4, 4       /* delay slot           */

    /* Clear BSS.
     */
    lw  t1, -12(t0) /* t1 <-- uboot_end_data_bootstrap  */
    lw  t2, -8(t0)  /* t2 <-- uboot_end_bootstrap       */
    add t1, t6      /* adjust pointers      */
    add t2, t6

    sub t1, 4
1:  addi    t1, 4
    bltl    t1, t2, 1b
    sw  zero, 0(t1) /* delay slot           */

    move    a0, a1
    la  t9, bootstrap_board_init_r
    j   t9
    move    a1, a2      /* delay slot           */

    .end    bootstrap_relocate_code



.globl  ath_ddr_tap_cal
.type   ath_ddr_tap_cal, @function

ath_ddr_tap_cal:
    li  a0, 0xbd001f00
    sw  zero,   0x0(a0)         // Place where the tap values are saved and used for SWEEP
    sw  zero,   0x4(a0)         // Place where the number of passing taps are saved.
    sw  zero,   0x14(a0)        // Place where the last pass tap value is stored
    li  a1, 0xaa55aa55      // Indicates that the First pass tap value is not found
    sw  a1, 0x10(a0)        // Place where the First pass tap value is stored
    nop

    li  a0, 0xb8060000      // RESET_BASE_ADDRESS
    lw  a1, 0x1c(a0)        // Reading the RST_RESET_ADDRESS
    li  a2, 0x08000000      // Setting the RST_RESET_RTC_RESET
    or  a1, a1, a2
    sw  a1, 0x1c(a0)

    li  a3, 0xffffffff
    xor a2, a2, a3
    and a1, a1, a2
    sw  a1, 0x1c(a0)        // Taking the RTC out of RESET
    nop

    li  a0, 0xb8107000      // RTC_BASE_ADDRESS
    li  a1, 0x1
    sw  a1, 0x0040(a0)      // RTC_SYNC_RESET_ADDRESS

    li  a2, 0x2

_poll_for_RTC_ON:
    lw  a1, 0x0044(a0)      // RTC_SYNC_STATUS_ADDRESS
    and a1, a2, a1
    bne a1, a2, _poll_for_RTC_ON


_CHANGE_TAPS:

    li  t0, 0xbd001f00      // Read the current value of the TAP for programming
    lw  t1, 0x0(t0)
    li  t2, 0x00000000
    or  t3, t1, t2


    li  t0, 0xb8000000      // DDR_BASE_ADDRESS

    sw  t3, 0x1c(t0)        // TAP_CONTROL_0_ADDRESS
    sw  t3, 0x20(t0)        // TAP_CONTROL_1_ADDRESS
    sw  t3, 0x24(t0)        // TAP_CONTROL_2_ADDRESS
    sw  t3, 0x28(t0)        // TAP_CONTROL_3_ADDRESS

    li  t1, 0x00000010      // Running the test 8 times
    sw  t1, 0x0068(t0)      // PERF_COMP_ADDR_1_ADDRESS

    li  t1, 0xfa5de83f      // 4 Row Address Bits, 4 Column Address Bits, 2 BA bits
    sw  t1, 0x002c(t0)      // PERF_MASK_ADDR_0_ADDRESS

#ifdef CONFIG_MACH_QCA953x
    li  t1, 0x0000ffff
    sw  t1, 0x0070(t0)      // PERF_COMP_AHB_GE0_1_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x0040(t0)      // PERF_COMP_AHB_GE1_0_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x0078(t0)      // PERF_COMP_AHB_GE1_1_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x0034(t0)      // PERF_MASK_AHB_GE0_0_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x006c(t0)      // PERF_MASK_AHB_GE0_1_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x003c(t0)      // PERF_MASK_AHB_GE1_0_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x0074(t0)      // PERF_MASK_AHB_GE1_1_ADDRESS

    li  t1, 0x0000ffff
    sw  t1, 0x0038(t0)      // PERF_COMP_AHB_GE0_0_ADDRESS
#else // Wasp & Scorpion ...
    li  t1, 0x545fc332
    sw  t1, 0x0070(t0)      // PERF_COMP_AHB_GE0_1_ADDRESS

    li  t1, 0xaba03ccd
    sw  t1, 0x0040(t0)      // PERF_COMP_AHB_GE1_0_ADDRESS

    li  t1, 0x545fc332
    sw  t1, 0x0078(t0)      // PERF_COMP_AHB_GE1_1_ADDRESS

    li  t1, 0xaba03ccd
    sw  t1, 0x0034(t0)      // PERF_MASK_AHB_GE0_0_ADDRESS

    li  t1, 0x545fc332
    sw  t1, 0x006c(t0)      // PERF_MASK_AHB_GE0_1_ADDRESS

    li  t1, 0xaba03ccd
    sw  t1, 0x003c(t0)      // PERF_MASK_AHB_GE1_0_ADDRESS

    li  t1, 0x545fc332
    sw  t1, 0x0074(t0)      // PERF_MASK_AHB_GE1_1_ADDRESS

    li  t1, 0xaba03ccd
    sw  t1, 0x0038(t0)      // PERF_COMP_AHB_GE0_0_ADDRESS
#endif

    li  t1, 0x00000001
    sw  t1, 0x011c(t0)      // DDR_BIST_ADDRESS

    li  t2, 0x1
_bist_done_poll:
    lw  t1, 0x0120(t0)      // DDR_BIST_STATUS_ADDRESS
    and t1, t1, t2
    bne t1, t2, _bist_done_poll

    lw  t1, 0x0120(t0)      // DDR_BIST_STATUS_ADDRESS
    li  t4, 0x000001fe
    and t2, t1, t4
    srl t2, t2, 0x1     // no. of Pass Runs

    li  t5, 0x00000000
    sw  t5, 0x011c(t0)      //DDR_BIST_ADDRESS  - Stop the DDR BIST test

    li  t5, 0x0001fe00
    and t5, t5, t1
    bnez    t5, _iterate_tap        // This is a redundant compare but nevertheless - Comparing the FAILS

    lw  t1, 0x0068(t0)      // PERF_COMP_ADDR_1_ADDRESS
    li  t3, 0x000001fe
    and t3, t3, t1
    srl t3, t3, 0x1     // No. of runs in the config register.

    bne t3, t2, _iterate_tap

pass_tap:
    li  t0, 0xbd001f00
    lw  t1, 0x4(t0)
    addiu   t1, t1, 0x1
    sw  t1, 0x4(t0)

    li  t0, 0xbd001f10
    lw  t1, 0x0(t0)
    li  t2, 0xaa55aa55
    beq t1, t2, _first_pass
    nop
    li  t0, 0xbd001f00
    lw  t1, 0x0(t0)
    li  t0, 0xbd001f10
    sw  t1, 0x4(t0)
    nop
    b   _iterate_tap
    nop

_first_pass:
    li  t0, 0xbd001f00
    lw  t1, 0x0(t0)
    li  t0, 0xbd001f10
    sw  t1, 0x0(t0)
    sw  t1, 0x4(t0)
    nop

_iterate_tap:

    li  t0, 0xbd001f00
    lw  t1, 0x0(t0)
    li  t2, 0x3f
    beq t1, t2, _STOP_TEST
    nop
    addiu   t1, t1, 0x1
    sw  t1, 0x0(t0)
    nop
    b   _CHANGE_TAPS

_STOP_TEST:
    li  t0, 0xbd001f00
    lw  t1, 0x4(t0)
    bnez    t1, _load_center_tap
    nop
    li  t3, 0x8         // Default Tap to be used
    b   _load_tap_into_reg

_load_center_tap:
    li  t0, 0xbd001f10
    lw  t1, 0x0(t0)
    lw  t2, 0x4(t0)
    add t3, t1, t2
    srl t3, t3, 0x1
    li  t4, 0x3f
    and t3, t3, t4
_load_tap_into_reg:
    li  t0, 0xb8000000
    sw  t3, 0x1c(t0)        // TAP_CONTROL_0_ADDRESS
    sw  t3, 0x20(t0)        // TAP_CONTROL_1_ADDRESS
    sw  t3, 0x24(t0)        // TAP_CONTROL_2_ADDRESS
    sw  t3, 0x28(t0)        // TAP_CONTROL_3_ADDRESS
    jr  ra
    nop



    /* Exception handlers.
     */
romReserved:
    b romReserved

romExcHandle:
    b romExcHandle
